#!/bin/bash

# ----------------------------------------------------------------------
# Filename:   ftp_anon_limited.sh
# Version:    1.0
# Date:       2013/06/24
# Author:     huijing.hei
# Email:      huijing.hei@cs2c.com.cn
# Summary:    02系统基本功能-04网络服务-01vsftp-01字符模式-02匿名用户-02限制某些匿名用户
# Notes:       ***
# Copyright:    China Standard Software Co., Ltd.
# History：     
#             Version 1.0, 2013/06/24
#             - Allow anonymous login, but limited some.
# ----------------------------------------------------------------------
##! @TODO:  update vsftpd.conf, and restart vsftpd
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure

function do_setup()
{
    serv=vsftpd
    RHOST=${RHOST}

    TEST_USER="anonymous"
    TEST_USER_PASSWD="noone@nowhere.com"
    VSFTP_DIR="/etc/vsftpd"
    VSFTP_CONF="$VSFTP_DIR/vsftpd.conf"

    exists expect ftp vsftpd
    EchoResult "check commands"


    # local, create tmp file , for upload

    TMP_DIR="/tmp/vsftp$$"
    mkdir -p $TMP_DIR
    EchoResult "mkdir $TMP_DIR"

    echo "test" > $TMP_DIR/upfile


    # remote, create banned_emails

    BANNED_EMAILS="$VSFTP_DIR/banned_emails"
    ${RSH} -l root -n $RHOST "echo 11$TEST_USER_PASSWD > $BANNED_EMAILS"
    EchoResult "remote, create banned_emails"


    # remote, create anon dir, and tmp file for download
    # ftpdir is for anonymous user to upload
    UP_DIR="/ftp-test/ftpdir"
    ${RSH} -l root -n $RHOST "mkdir -p $UP_DIR && chmod 777 $UP_DIR"
    EchoResult "remote, create anon upload dir $UP_DIR"

    TMP_FILE_READ_ALL="tmp_file_read_all"
    TMP_FILE_READ_NOT_ALL="tmp_file_read_not_all"
    ${RSH} -l root -n $RHOST "echo \"file 644\">$UP_DIR/$TMP_FILE_READ_ALL && chmod 644 $UP_DIR/$TMP_FILE_READ_ALL; \
                                    echo \"file 640\">$UP_DIR/$TMP_FILE_READ_NOT_ALL && chmod 640 $UP_DIR/$TMP_FILE_READ_NOT_ALL"


    # remote, add user ftptest

    CHOWN_USERNAME=ftptest
    CHOWN_USERNAME_PASSWD=qwer4321
    ${RSH} -n -l root $RHOST "/usr/sbin/userdel -rf $CHOWN_USERNAME; /usr/sbin/useradd $CHOWN_USERNAME"
    expect -c "
        spawn ssh root@$RHOST
            expect {
                \"yes/no\" { 
                     send \"yes\r\" 
                     expect \"password: \"
                     send \"$PASSWORD\r\"
                     }
                \"password: \" { 
                     send \"$PASSWORD\r\"
                     expect \"Permission denied\" { send_user \"ssh $RHOST failed\r\"; exit 1; }
                     }

            }

            sleep 2
            send \"LANG=C passwd $CHOWN_USERNAME\r\"
            expect {
                \"Unknown user name\" { send_user \"remote useradd $CHOWN_USERNAME failed.\n\"; exit 1; }
                \"ew password: \" { send \"$CHOWN_USERNAME_PASSWD\r\" }
            }

           expect \"type new password: \" 
           send \"$CHOWN_USERNAME_PASSWD\r\"

           expect {
               \"Enter new password: \" { send_user \"remote passwd $CHOWN_USERNAME failed.\n\"; exit 1;}
               \"passwd: all authentication tokens updated successfully.\n\" {send_user \"remote passwd $CHOWN_USERNAME success.\n\"}
               }

        expect eof
    "

    CHOWN_USERNAME_ID=`id -u $CHOWN_USERNAME`

    # remote, update vsftpd.conf, restart ftp service
    ${RSH} -l root -n $RHOST "cp $VSFTP_CONF $VSFTP_CONF.bak"
    TMP_VSFTP_CONF="/tmp/vsftpd.conf" 
    cat > ${TMP_VSFTP_CONF} <<-EOF
anonymous_enable=YES

local_enable=YES

write_enable=YES

local_umask=022

dirmessage_enable=YES

xferlog_enable=YES

connect_from_port_20=YES

xferlog_std_format=YES

chroot_local_user=NO

listen=YES

pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

anon_upload_enable=YES
deny_email_enable=YES
banned_email_file=/etc/vsftpd/banned_emails
anon_root=/ftp-test
anon_world_readable_only=YES
chown_uploads=YES
chown_username=ftptest
EOF

    ${RCP} $TMP_VSFTP_CONF root@$RHOST:$VSFTP_CONF
    # restart 
    ${RSH} -l root $RHOST \
       "command -v systemctl && /bin/systemctl restart ${serv}.service || /sbin/service ${serv} restart"

    RE=`${RSH} -l root $RHOST \
       "/bin/netstat -ntlp | grep ${serv}"`
    echo "${RE}" | grep ${serv}
    EchoResult "service ${serv} restart test."


    trap do_cleanup INT EXIT

}

##! @TODO:  upload and download file, create dir, rename and delete file.
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure

function do_test()
{
    echo "Test: anonymous limited login, upload and download files, can create dir, rename file and delete file."    

    # anonymous login failed, login with password in banned_emails
    expect -c "
        spawn ftp $RHOST
        expect -re \": \"
        send \"$TEST_USER\r\"
        expect -re \"Password:\"
        send \"11$TEST_USER_PASSWD\r\"
            expect {
                # 230 - Login successful
                \"230\" {send_user \"==> TEST : FAIL (ftp allowed login attempt)\n\";exit 1}
                # 530 - Login failed
                \"530\" {send_user \"==> TEST : PASS (ftp should reject login attempt)\n\"}
            }

        expect \"ftp> \"
       send \"bye\r\"

       expect eof

       catch wait result
       exit [lindex \$result 3]

       "

     # anonymous login success
     expect -c "
        spawn ftp $RHOST
        expect -re \": \"
        send \"$TEST_USER\r\"
        expect -re \"Password:\"
        send \"$TEST_USER_PASSWD\r\"

            expect {
                # 530 - Login failed
                \"530\" {send_user \"==> TEST : FAIL (ftp rejected login attempt)\n\";exit 1}
                # 230 - Login successful
                \"230\" {send_user \"==> TEST : PASS (ftp allowed login attempt)\n\"}
            }

       # ls
       expect \"ftp> \"
       send \"ls\r\"
        expect { 
            # ls - transfer successful
            \"ftpdir\" {send_user \"==> TEST : PASS anonymous change anon_root.\n\"}
        }

       # lcd
       expect \"ftp> \"
       send \"lcd $TMP_DIR\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL anonymous lcd.\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS anonymous lcd.\n\"}
        }

       # cd
       expect \"ftp> \"
       send \"cd ftpdir\r\"
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL anonymous cd.\n\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS anonymous cd.\n\"}
        }

       # get 640 failed
       expect \"ftp> \"
       send \"get $TMP_FILE_READ_NOT_ALL\r\"
        expect { 
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : FAIL anonymous get file 640.\n\"; exit 1 }
            # 550 - Failed to open file
            \"550\" { send_user \"==> TEST : PASS anonymous not allowed to get file 640.\n\n\" }
        }

       # get 644 success
       expect \"ftp> \"
       send \"get $TMP_FILE_READ_ALL\r\"
        expect { 
            # 550 - Failed to open file
            \"550\" { send_user \"==> TEST : FAIL anonymous not allowed to get file 644.\n\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS anonymous get file 644 success.\n\" }
        }

       # put upfile
       expect \"ftp> \"
       send \"put upfile\r\" 
        expect { 
            # 550 - failed
            \"550\" { send_user \"==> TEST : FAIL anonymous put file.\n\";exit 1 }
            # 553 - failed
            \"553\" { send_user \"==> TEST : FAIL anonymous put file.\n\";exit 1 }
            # 226 - transfer successful
            \"226\" {send_user \"==> TEST : PASS anonymous put file.\n\"}
        }

       #check owner
       expect \"ftp> \"
       send \"ls upfile\r\" 
        expect { 
            # ls
            \"${CHOWN_USERNAME_ID}\" { send_user \"==> TEST : PASS file owner is ${CHOWN_USERNAME}.\n\" }
        }


       expect \"ftp> \"
       send \"mkdir testdir\r\"
        expect { 
            # 257 - create dir successful
            \"257\" {send_user \"==> TEST : FAIL anonymous create dir.\n\"; exit 1 }
            # 550 - failed
            \"550\" { send_user \"==> TEST : PASS anonymous should not allowed to create dir.\n\" }
        }
       

       expect \"ftp> \"
       send \"rename upfile upfile.bak\r\"
        expect { 
            # 250 - rename file
            \"250\" {send_user \"==> TEST : FAIL anonymous rename file.\n\"; exit 1 }
            # 550 - failed
            \"550\" { send_user \"==> TEST : PASS anonymous should not allowed to rename file.\n\" }
        }

       expect \"ftp> \"
       send \"delete upfile\r\"       
        expect { 
            # 250 - rename file
            \"250\" {send_user \"==> TEST : FAIL anonymous delete file.\n\"; exit 1 }
            # 550 - failed
            \"550\" { send_user \"==> TEST : PASS anonymous should not allowed to delete file.\n\" }
        }

       expect \"ftp> \"
       send \"bye\r\"

       expect eof

       catch wait result
       exit [lindex \$result 3]

    "
}

##! @TODO:  cleanup tmp files, back up vsftpd.conf and restart ftp services.
##! @AUTHOR: huijing.hei
##! @VERSION: 1.0 
##! @OUT: 0 => success; 1 => failure
function do_cleanup()
{
    ${RSH} -l root -n $RHOST "[ -f $VSFTP_CONF.bak ] && mv -f $VSFTP_CONF.bak $VSFTP_CONF"
    ${RSH} -l root -n $RHOST "command -v systemctl && /bin/systemctl stop ${serv}.service || /sbin/service ${serv} stop"
    ${RSH} -l root -n $RHOST "/usr/sbin/userdel -rf $CHOWN_USERNAME; rm -rf /ftp-test; rm -f $BANNED_EMAILS"

    rm -rf $TMP_DIR $TMP_VSFTP_CONF

}
# include lib files

if [ -z "$SFROOT" ]
then
    CMDLIB=./
    SFROOT=./
else
    CMDLIB=${SFROOT}/testcases/Network_Service
fi

. ${SFROOT}/lib/Echo.sh
. ${CMDLIB}/lib/Net.sh
. ${SFROOT}/lib/XmlParse.sh

. ${CMDLIB}/setup.sh

# get RHOST, RUSERNAME, PASSWORD from config.xml
DATA_FILE="${SFROOT}/testcases/Network_Service/config.xml"
[ -e $DATA_FILE ] || { echo "$DATA_FILE not find, test end."; exit 1; }

XmlParse ${DATA_FILE}

GetValue REHOST ReHost
GetValue RUSERNAME UserName
GetValue PASSWORD RootPasswd

export RHOST=${REHOST}
export RUSERNAME=${RUSERNAME}
export PASSWORD=${PASSWORD}


setup_env || { echo "setup env failed, test end."; exit 1; }

do_setup
do_test || { echo "testcase failed."; exit 1; }
